/* Copyright © Worklight Ltd. 2006-2011.  All rights reserved. */

package com.worklight.wlclient;

import java.net.SocketTimeoutException;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;

import android.os.Build;

import com.worklight.wlclient.api.WLErrorCode;
import com.worklight.wlclient.api.WLFailResponse;
import com.worklight.wlclient.api.WLResponse;

 
/**
 * This class used for send asynchronous request in separate thread
 */
public class AsynchronousRequestSender implements Runnable {
	
	private WLRequest request;
	private HttpClient httpClient = null;
	protected AsynchronousRequestSender(WLRequest request) {
		this.request = request;
		httpClient = new DefaultHttpClient();
	}
 
	public void run() {
		WLClientUtils.debug("Sending request " + request.getPostRequest().getURI());
		HttpResponse httpResponse;
		try {
			setUserAgentHeader(httpClient);
			setConnectionTimeout (httpClient);
			WLCookieManager.addCookies(request);
			httpResponse = httpClient.execute(request.getPostRequest(),request.getHttpContext());
			onResponseReceived(httpResponse);
		} 
		catch (SocketTimeoutException e) {
			WLClientUtils.error("Request timeout: " + request.getPostRequest().getURI(), e);
			request.getRequestListener().onFailure(new WLFailResponse(WLErrorCode.REQUEST_TIMEOUT, WLErrorCode.REQUEST_TIMEOUT.getDescription(), request.getOptions()));
		} 
		catch (ConnectTimeoutException e) {
			WLClientUtils.error("Host " + request.getPostRequest().getURI().getHost() + " is not responsive for url " + request.getPostRequest().getURI(), e);
			request.getRequestListener().onFailure(new WLFailResponse(WLErrorCode.UNRESPONSIVE_HOST, WLErrorCode.UNRESPONSIVE_HOST.getDescription(), request.getOptions()));
		}
		catch (Exception e) {
			WLClientUtils.error("Exception thrown while trying to execute a request to " + request.getPostRequest().getURI(), e);
			request.getRequestListener().onFailure(new WLFailResponse(WLErrorCode.UNEXPECTED_ERROR, WLErrorCode.UNEXPECTED_ERROR.getDescription(), request.getOptions()));
		} 
	}
	
	/**
	 * Set the connection timeout
	 * @param httpClient
	 */
	private void setConnectionTimeout(HttpClient httpClient) {
		HttpConnectionParams.setSoTimeout(httpClient.getParams(), request.getOptions().getTimeout());
		HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), request.getOptions().getTimeout());
	}

	/**
	 * Add android native to user-agent
	 * @param httpClient
	 */
	private void setUserAgentHeader(HttpClient httpClient) {
		String userAgent = (String)httpClient.getParams().getParameter("http.useragent");
		httpClient.getParams().setParameter(
		    "http.useragent",
		    userAgent + " WLNativeAPI(" + 
		    	Build.DEVICE + "; " + 
		    	Build.DISPLAY + "; " + 
		    	Build.MODEL + "; SDK " + 
		    	Build.VERSION.SDK + "; Android " + 
		    	Build.VERSION.RELEASE + ")" 
		);
	}
	
	private void onResponseReceived(HttpResponse httpResponse) {
		if (httpResponse == null) {
			WLClientUtils.error("Exception thrown while trying to execute a request to " + request.getPostRequest().getURI());
			request.getRequestListener().onFailure(new WLFailResponse(WLErrorCode.UNEXPECTED_ERROR, WLErrorCode.UNEXPECTED_ERROR.getDescription(), request.getOptions()));
			return;
		}
		
		WLResponse response = null;
		WLCookieManager.handleResponseHeaders(httpResponse.getAllHeaders(), request.getPostRequest().getURI());
		
		// Response status code is not successful 
		if (httpResponse.getStatusLine().getStatusCode() < 200 || httpResponse.getStatusLine().getStatusCode() > 300){
			response = new WLFailResponse(httpResponse); 
			response.setOptions(request.getOptions());
			request.getRequestListener().onFailure((WLFailResponse)response);
			WLClientUtils.debug("Response received with bad status " + response.getStatus() + " " + response);
			return;
		} 
		else {
			// in case response return with success code (200 <= code < 300)
			response = new WLResponse(httpResponse);
			response.setOptions (request.getOptions());
			// call the auth handler if not null and if the return data isLoginForm
			if (request.getAuthListener() != null && request.getAuthListener().isLoginFormResponse(response)) {
				request.getAuthListener().handleLoginResponse (response);			
			} 
			else {
				// call the on success of the request listener
				request.getRequestListener().onSuccess(response);
			}
			WLClientUtils.debug("Response recived with OK status " + response.getStatus() + " " + response);
		}
	}
}